'''
Created on 2012-8-5

@author: DXD.Spirits
'''

"""
How to mesure the performance ?
    Execution Time
    Arcs/Nodes visited
    SQL queries sent
"""


#import bisect
import random, time
from algorithms import shortestpath
from shortcuts import log_info, execute_select
import graph_connector
#import gexf
#import gexf_dynamic


def get_next_time(arc, cur_time, dep_node = None, arr_node = None, route = None):
    dataset_id, arc_id = arc
    
    results = execute_select("""
        SELECT dep_time, arr_time
        FROM gtfs_graph_timetable
        WHERE dataset_id = %d AND arc_id = %d AND dep_time >= %d
        ORDER BY dep_time
        LIMIT 1
    """ % (dataset_id, arc_id, cur_time))
    if results is not None and results:
        return int(results[0][0]), int(results[0][1])
    else:
        return None


INIT = [3600*10, 0, 0]
#INF = [3600*15, 300*5, 5]
#INIT = [0, 0, 0]
INF = [0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF]

def cost_function(labelval, arcval):
    ''' labelval = [arrivaltime, walkingtime, changes]
    '''
    
    def value(arr_time, walking_time, transfer):
        if arr_time > INF[0] or walking_time > INF[1] or transfer > INF[2]:
            return inf()
        else:
            return [arr_time, walking_time, transfer]
    
    def inf():
        return [0xFFFFFFFF] * 3
    
    if "route_arc" in arcval:
        cur_time = labelval[0]
        arc = arcval["route_arc"]
        next_time = get_next_time(arc, cur_time)
        if next_time == None:
            return inf()
        else:
            _dep_time, arr_time = next_time
            return value(arr_time, labelval[1], labelval[2])
    elif "transfer_arc" in arcval:
        transfer = arcval["transfer_arc"]
        return value(labelval[0], labelval[1], labelval[2] + transfer)
    elif "walking_arc" in arcval:
        walking_time = arcval["walking_arc"]
        return value(labelval[0] + walking_time, labelval[1] + walking_time, labelval[2] + 1)
    else:
        return value(labelval[0], labelval[1], labelval[2])


def search_path(dataset_name, origin, destin, pre_fetch = True):

    log_info("Travel: %s -> %s With route pre-fetching? %s" % (str(origin), str(destin), pre_fetch))
    
    if pre_fetch:
        route_set = search_connectivity(dataset_name, origin, destin)
        graph = graph_connector.load_query_graph(route_set)
    else:
        graph = graph_connector.load_query_graph()
    
    origin = origin + ("enter",)
    destin = destin + ("exit",)
    
    if len(graph) > 0 and origin in graph and destin in graph:
        path_list, _node_sequence = shortestpath.martins(graph, origin, destin, 
                                                         costfunc = cost_function, K = 3, 
                                                         init = INIT, inf = INF)
#        for cost, path in path_list:
#            arrival = "%02d:%02d:%02d" % (cost[0] / 3600, cost[0] % 3600 / 60, cost[0] % 60)
#            log_info("A%s, W%03d, T%d: %s" % (arrival, cost[1], cost[2], path))
        for cost, _path in path_list:
            arrival = "%02d:%02d:%02d" % (cost[0] / 3600, cost[0] % 3600 / 60, cost[0] % 60)
            log_info("A%s, W%03d, T%d" % (arrival, cost[1], cost[2]))
    else:
        path_list = []
    
    log_info("------------------------------Travel End------------------------------")
    
    #graph_name = "%s-%s_%s" % (origin, destin, ["without_prefetch", "with_prefetch"][pre_fetch])
    #gexf_dynamic.output_martins_sequence([dataset_name], graph_name + "_sequence", node_sequence)
    #path_list = [path for _cost, path in path_list]
    #if len(path_list) > 0:
    #    gexf.output_martins_solution([dataset_name], graph_name + "_1", path_list[0:3])
    #    gexf_dynamic.output_martins_solution([dataset_name], graph_name + "_1", path_list[0:3], node_sequence)
    #if len(path_list) > 3:
    #    gexf.output_martins_solution([dataset_name], graph_name + "_2", path_list[3:6])
    #    gexf_dynamic.output_martins_solution([dataset_name], graph_name + "_2", path_list[3:6], node_sequence)
    #if len(path_list) > 6:
    #    gexf.output_martins_solution([dataset_name], graph_name + "_3", path_list[6:9])
    #    gexf_dynamic.output_martins_solution([dataset_name], graph_name + "_3", path_list[6:9], node_sequence)
    
    return len(graph), len(path_list)



def search_connectivity(dataset_name, origin, destin):
    
    graph = graph_connector.load_local_graph(dataset_name, walking = True)
    
    path, _cost = shortestpath.dijkstra(graph, origin, destin)
    
    where_clause = " ".join(["OR (arc.dataset_id = %d AND arc.dep_node = %d)" % node for node in path] +
                            ["OR (arc.dataset_id = %d AND arc.arr_node = %d)" % node for node in path])
    
    results = execute_select("""
        SELECT DISTINCT arc.dataset_id, arc.route
        FROM gtfs_graph_arcs AS arc 
        WHERE 0 %s
    """ % where_clause)
    route_set = {(int(dataset_id), int(route_id)) for dataset_id, route_id in results}
    
    log_info("%d routes pre fetched" % len(route_set))
    
    #graph_name = "%s-%s_prefetehed_routes" % (origin, destin)
    #gexf.output_prefetched_routes([dataset_name], graph_name, path, route_set)
    
    return route_set


def testNYC():
    nodesize=[0,0,490,141,3552,13,3682,124,0,219]
    
    ds = [2,3,4,5,6,7,9]
    #ds = [2,3,5,7,9]
    #ds = [2, 3, 5]
    
    dataset = 'gtfs'
    
    g1 = g2 = 0
    p1 = p2 = 0.0
    t1 = t2 = 0.0
    N = 10
    
    for _iiiii in range(N):
        i = random.choice(ds)
        j = random.choice(ds)
        
        origin = (i, random.randint(1, nodesize[i]))
        destin = (j, random.randint(1, nodesize[j]))
        
        start = time.time()
        graph_size, path_size = search_path(dataset, origin, destin, True)
        end = time.time()
        g1 += graph_size
        p1 += path_size
        t1 += (end - start)
        
        start = time.time()
        graph_size, path_size = search_path(dataset, origin, destin, False)
        end = time.time()
        g2 += graph_size
        p2 += path_size
        t2 += (end - start)
    
    log_info("network_size  %d" % (sum([nodesize[i] for i in ds])))
    log_info("graph_size: %d  solution_size: %.3f  running time: %.3f" % (g1 / N, p1 / N, t1 / N))
    log_info("graph_size: %d  solution_size: %.3f  running time: %.3f" % (g2 / N, p2 / N, t2 / N))


if __name__ == "__main__":
    
    testNYC()
    exit()
    
    nodesize=[0,0,50679]
    ds = [2]
    dataset = 'gtfs'
    
    g1 = g2 = 0
    p1 = p2 = 0.0
    t1 = t2 = 0.0
    N = 10
    
    for _iiiii in range(N):
        i = random.choice(ds)
        j = random.choice(ds)
        
        origin = (i, random.randint(1, nodesize[i]))
        destin = (j, random.randint(1, nodesize[j]))
        
        start = time.time()
        graph_size, path_size = search_path(dataset, origin, destin, True)
        end = time.time()
        g1 += graph_size
        p1 += path_size
        t1 += (end - start)
    
    log_info("network_size  %d" % (sum([nodesize[i] for i in ds])))
    log_info("graph_size: %d  solution_size: %.3f  running time: %.3f" % (g1 / N, p1 / N, t1 / N))
